package org.zhaolei.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
//import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zhaolei.constant.CacheKey;
import org.zhaolei.enums.BizCodeEnum;
import org.zhaolei.enums.SendCodeEnum;
import org.zhaolei.feign.CouponFeignService;
import org.zhaolei.interceptor.LoginInterceptor;
import org.zhaolei.mapper.UserMapper;
import org.zhaolei.model.AddressDO;
import org.zhaolei.model.LoginUser;
import org.zhaolei.model.UserDO;
import org.zhaolei.request.NewUserCouponRequest;
import org.zhaolei.request.UserLoginRequest;
import org.zhaolei.request.UserRegisterRequest;
import org.zhaolei.service.NotifyService;
import org.zhaolei.service.UserService;
import org.zhaolei.util.CommonUtil;
import org.zhaolei.util.JWTUtil;
import org.zhaolei.util.JsonData;
import org.zhaolei.vo.UserVO;

import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private NotifyService notifyService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CouponFeignService couponFeignService;
    /**
     * 用户注册
     * 邮箱验证码验证
     * 密码加密
     * 账号唯一性检查
     * 插入数据库
     * 新注册用户福利发放
     * @param registerRequest
     * @return
     */
    @Override
//    @GlobalTransactional
    public JsonData register(UserRegisterRequest registerRequest) {
        boolean checkCode = false;
        if (StringUtils.isNotBlank(registerRequest.getMail())) {
            if (notifyService.checkCode(SendCodeEnum.USER_REGISTER, registerRequest.getMail(), registerRequest.getCode())) {
                checkCode = true;
            }
        }
        if (!checkCode) {
            //返回验证码错误
            return JsonData.buildResult(BizCodeEnum.CODE_ERROR);
        }

        UserDO userDO = new UserDO();
        //把参数中的属性copy到userDO中来
        BeanUtils.copyProperties(registerRequest, userDO);

        userDO.setCreateTime(new Date());
        userDO.setSlogan("人生需要动态规划，学习需要贪心算法");

        //设置密码
        //userDO.setPwd(registerRequest.getPwd());
        //先生成密码的盐
        userDO.setSecret("$1$" + CommonUtil.getStringNumRandom(8));

        //密码和盐结合，然后进行加密，生成加密后的密码 //这里用userDO也行，因为对象属性都复制过来了
        String crtpyPwd = Md5Crypt.md5Crypt(registerRequest.getPwd().getBytes(), userDO.getSecret());
        userDO.setPwd(crtpyPwd);


        //账号唯一性检查  TODO
        if (checkUnique(userDO.getMail())) {
            int rows = userMapper.insert(userDO);
            log.info("rows:{},注册成功:{}", rows, userDO.toString());
            //新用户注册成功，初始化信息，发放福利等
            userRegisterInitTask(userDO);

            //模拟异常
//            int b = 1 / 0;


            return JsonData.buildSuccess();
        } else {
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_REPEAT);
        }

    }

    /**
     * 1. 根据mail去找是否有这条记录
     * 2. 有的话，用密钥+用户传递的明文密码进行加密，再和数据库的密文进行匹配
     *
     * @param userLoginRequest
     * @return
     */
    @Override
    public JsonData login(UserLoginRequest userLoginRequest) {
//        AddressDO addressDO = addressMapper.selectOne(new QueryWrapper<AddressDO>().eq("id", id));
        UserDO userDO = userMapper.selectOne(new QueryWrapper<UserDO>().eq("mail", userLoginRequest.getMail()));
        if (userDO == null) {
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_UNREGISTER);
        }
        //明文密码是用户传递来的，盐是保存在数据库的
        String cryptPwd = Md5Crypt.md5Crypt(userLoginRequest.getPwd().getBytes(), userDO.getSecret());
        if (cryptPwd.equals(userDO.getPwd())) {
            //登录成功，生成token
//            LoginUser loginUser = new LoginUser();
            LoginUser loginUser = LoginUser.builder().build();
            BeanUtils.copyProperties(userDO, loginUser);

            String token = JWTUtil.geneJsonWebToken(loginUser);
            return JsonData.buildSuccess(token);
        } else {
            //密码错误，登录失败
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_PWD_ERROR);
        }
    }

    @Override
    public UserVO findUserDetail() {
        //怎么知道当前的用户是谁呢？用threadLocal
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        UserDO userDO = userMapper.selectOne(new QueryWrapper<UserDO>().eq("id", loginUser.getId()));
        if (userDO != null) {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(userDO, userVO);
            return userVO;
        }

        return null;
    }

    /**
     * 检查账号是否唯一
     * @param mail
     * @return
     */
    private boolean checkUnique(String mail) {
        QueryWrapper queryWrapper = new QueryWrapper<UserDO>().eq("mail", mail);

        List<UserDO> userDOList = userMapper.selectList(queryWrapper);

        return userDOList.isEmpty();
    }

    /**
     * 用户注册，初始化福利信息 TODO
     * @param userDO
     */
    private void userRegisterInitTask(UserDO userDO) {
        NewUserCouponRequest newUserCouponRequest = new NewUserCouponRequest();
        newUserCouponRequest.setUserId(userDO.getId());
        newUserCouponRequest.setName(userDO.getName());
        JsonData jsonData = couponFeignService.addNewUserCoupon(newUserCouponRequest);
        //如果不加判断，那么下游服务失败就不知道了，加了这个判断就能放开全局异常捕获了
        //解决分布式事务在全局异常下失效的问题
        if (jsonData.getCode() != 0) {
            throw new RuntimeException("发放优惠券异常");
        }

        log.info("发放新用户注册优惠券：{},结果：{}", newUserCouponRequest.toString(), jsonData.toString());
    }
}
